<?php
require_once 'Zend/Search/Lucene.php';
/**
 * This class is responsible for interfacing with the Zend
 * Search Lucene library.
 *
 * @author Rob Young <rob@roryoung.co.uk>
 * @package forage.engine.zsl
 */
class ForageZslEngine extends ForageEngine implements ForageEngineModifiable, ForageEngineSearchable
{
  private $path;
  private $index;
  private $config;

  public function initialize($dsn, $config)
  {
    $this->path   = $dsn;
    $this->config = $config;
  }

  public function search($query)
  {
    if (!($query instanceof ForageQuery)) {
      throw new InvalidArgumentException("Expecting a ForageQuery");
    }
    $user_query = Zend_Search_Lucene_Search_QueryParser::parse($query->query_string);
    $index      = $this->getIndex();
    $hits       = $index->find($user_query);
    $hit_count  = count($hits);
    $response   = new ForageResponse();
    $response->setTotal($hit_count);
    for ($i=$query->start_index, $c=$query->end_index; $i<$c; $i++) {
      $response[] = $this->convertToForageDocument($hits[$i]->getDocument());
    }
    return $response;
  }

  public function add(ForageDocument $document) {
    $this->remove($document);
    $zend_document = $this->convertToZslDocument($document);
    $index = $this->getIndex();
    $index->addDocument($zend_document);
  }

  public function remove(ForageDocument $document)
  {
    $index = $this->getIndex();
    $id_fields = $document->getFieldsByProperty('uid', true);
    if (!$id_fields) {
      throw new ForageZslException("Expecting a UID field, at least one field must have the uid property set.");
    }
    $query = new Zend_Search_Lucene_Search_Query_Boolean();
    foreach ($id_fields as $id_field) {
      $query->addSubquery(
        new Zend_Search_Lucene_Search_Query_Term(
          new Zend_Search_Lucene_Index_Term($id_field->value, $id_field->name)
        ), true
      );
    }
    $hits = $index->find($query);
    foreach ($hits as $hit) {
      $index->delete($hit->id);
    }
  }

  public function flush()
  {
  }

  public function optimize()
  {
    $this->getIndex()->optimize();
  }

  private function getIndex()
  {
    if (!isset($this->index)) {
      if (!file_exists($this->path)) {
        $this->index = Zend_Search_Lucene::create($this->path);
      } else {
        $this->index = Zend_Search_Lucene::open($this->path);
      }
    }
    return $this->index;
  }

  private function convertToZslDocument(ForageDocument $document)
  {
    $zsl_document = new Zend_Search_Lucene_Document();
    foreach ($document->fields as $field) {
      if ($field->getProperty('stored', true)) {
        $zsl_document->addField(Zend_Search_Lucene_Field::Text($field->name, utf8_encode($field->value)));
      } else {
        $zsl_document->addField(Zend_Search_Lucene_Field::UnStored($field->name, utf8_encode($field->value)));
      }
    }
    return $zsl_document;
  }

  private function convertToForageDocument(Zend_Search_Lucene_Document $document)
  {
    $forage_document = new ForageDocument();
    $forage_document->setProperty('boost', $document->boost);
    foreach ($documents->getFieldNames() as $name) {
      $field = $documents->getField($name);
      $forage_field = new ForageField($name, $field->getUtf8Value());
      $forage_field->setProperty('indexed', $zsl_field->isIndexed);
      $forage_field->setProperty('stored', $zsl_field->isStored);
      $forage_document->add($forage_field);
    }
    return $forage_document;
  }
}

class ForageZslException extends ForageException {}
